STM32之IO口模拟IIC 您所在的位置:网站首页 stm32 IIC速度 STM32之IO口模拟IIC

STM32之IO口模拟IIC

2024-02-25 14:25| 来源: 网络整理| 查看: 265

本文介绍如何使用STM32标准外设库的GPIO端口模拟IIC,本例程使用PB6和PB7模拟一路IIC。

本文适合对单片机及C语言有一定基础的开发人员阅读,MCU使用STM32F103VE系列。

  1.    简介

IIC (Inter-Integrated Circuit)总线,也可写作I2C,是PHILIPS 公司开发的两线式串行总线,用于多设备之间通讯,分为主机Master和从机Slave,主机和从机可以有多个,但一般情况下只有一个主机,从机之间可以通过地址进行区分,不同种类的设备地址不同,如果同时接入多个相同种类的设备,可以通过片选信号对从机进行选择。通讯只能由主机发起,支持的操作分为读取和写入,即主机读取从机的数据,以及向从机写入数据。

I2C两线分别是时钟线SCL和数据线SDA,其中SCL和SDA均由主机控制,可以设置成开漏输出模式。

2.    协议说明 2.1. 总线传输信号 空闲状态:IIC空闲状态时SCL和SDA均输出高电平,初始状态以及发送结束信号之后均为空闲状态。 开始信号:START,简写S,SCL为高电平,SDA由高电平向低电平跳变。 结束信号:STOP,简写P,SCL为高电平,SDA由低电平向高电平跳变。 从机地址:SLAVE_ADDRESS,每种从机都有一个表示该设备的地址,地址一般为7位,主机发起通讯时,通过 SDA 信号线发送设备地址(SLAVE_ADDRESS)来查找从机,紧跟设备地址的一个数据位用来表示数据传输方向(R/W位),数据方向位为“1”时表示主机由从机读数据,数据方向位为“0”时表示主机向从机写数据。从机接收到匹配的地址后,会返回一个应答(ACK)信号,只有接收到应答信号后,主机才能继续发送或接收数据。 响应信号:ACK/NACK,简写A,响应包括应答(ACK)和非应答(NACK),当数据接收端时,当设备(无论主从机)接收到 I2C 传输的一个字节数据或地址后,若希望对方继续发送数据,则需要向对方发送“应答(ACK)”信号,即SDA为低电平,发送方会继续发送下一个数据;若接收端希望结束数据传输,则向对方发送“非应答(NACK)”信号,即SDA为高电平,发送方接收到该信号后会产生一个停止信号,结束信号传输。 主机写入:SCL为高电平时,SDA有效,SDA为输出模式,主机控制SDA输出高电平时表示写入1,SDA输出低电平时表示写入0。 主机读取:SCL为高电平时,SDA有效,SDA为输入模式,主机读取SDA高电平时表示输入1,SDA低电平时表示输入0。此时主机释放对 SDA 信号线的控制,由从机控制 SDA 信号线,主机接收信号。 2.2. 基本读写过程 写数据:主机先发一个开始信号(S),然后发送从机地址(SLAVE ADDRESS),后续跟上写信号(R/W位为0),然后等待从机的应答信号(ACK位为0),主机向从机传输数据(DATA),数据包为1个字节共8位,从高位到低位依次发送,主机每发送完1个字节数据,都要等待从机的应答信号(ACK),重复这个过程,可以向从机传输 N 个数据,当数据传输结束时,主机向从机发送一个停止传输信号(P),表示不再传输数据。 读数据:主机先发一个开始信号(S),然后发送从机地址(SLAVE ADDRESS),后续跟上读信号(R/W位为1),然后等待从机的应答信号(ACK位为0),主机从从机读取数据(DATA),数据包为1个字节共8位,从高位到低位依次发送,从机每发送完1个字节数据,都要等待主机的应答信号(ACK),重复这个过程,可以从从机读取 N 个数据,当主机希望停止接收数据时,就向从机返回一个非应答信号(NACK),则从机自动停止数据传输,主机再向从机发送一个停止传输信号(P),表示不再传输数据。 读和写数据:除了基本的读写,I2C 通讯还有一种是复合读写模式,该传输过程有两次起始信号(S)。一般在第一次传输中,主机通过 SLAVE_ADDRESS 寻找到从设备后,发送一段“数据”,这段数据通常用于表示从设备内部的寄存器或存储器地址(注意区分它与 SLAVE_ADDRESS 的区别);在第二次的传输中,对该地址的内容进行读或写。也就是说,第一次通讯是告诉从机读写地址,第二次则是读写的实际内容。

  

2.3. 速度模式

标准模式传输速率为100kbit/s,即10us可以传输一个bit,如果用GPIO模拟I2C时电平变换时需要增加适当的延时。

3.    初始化

初始化跟普通GPIO类似,只是输出模式设置为开漏输出。

其中SCL始终输出信号,但SDA需要支持输出信号和读取信号,当设置为开漏输出时,如果需要输出信号,则正常输出即可,如果需要读取信号,则MCU将SDA输出高电平,此时如果从机输出低电平,则SDA被拉低,此时MCU可以读到低电平。即GPIO引脚为开漏输出模式时,MCU输出高电平时,即释放了该引脚的控制,此时该引脚的电平取决于从机的输出,且MCU仍可以读取该引脚的电平。

GPIO初始化完成之后,可以将SCL和SDA置为高电平,即释放该引脚的控制,如果总线上有多个主机,则不会干扰其他设备的通讯。

4.    信号模拟

需要按照通讯信号的时序,实现START、STOP、ACK、NACK、Read、Write和WaitAck信号。

 

完整代码(仅自己编写的部分) 1 #define IIC_SCL_1 GPIO_SetBits(GPIOB, GPIO_Pin_6) /* SCL = 1 */ 2 #define IIC_SCL_0 GPIO_ResetBits(GPIOB, GPIO_Pin_6) /* SCL = 0 */ 3 4 #define IIC_SDA_1 GPIO_SetBits(GPIOB, GPIO_Pin_7) /* SDA = 1 */ 5 #define IIC_SDA_0 GPIO_ResetBits(GPIOB, GPIO_Pin_7) /* SDA = 0 */ 6 7 #define IIC_READ_SDA() GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_7) /* 读SDA口线状态 */ 8 9 //初始化IIC 10 void IIC_Init(void) 11 { 12 GPIO_InitTypeDef GPIO_InitStructure; 13 14 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); 15 16 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7; 17 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD ; //开漏输出 18 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 19 GPIO_Init(GPIOB, &GPIO_InitStructure); 20 21 IIC_Stop(); 22 } 23 24 //产生IIC起始信号 25 //SCL为高电平时SDA由高变低 26 /* 27 SCL: ̄ ̄ ̄ ̄ ̄\_ 28 SDA: ̄ ̄\____ 29 */ 30 void IIC_Start(void) 31 { 32 IIC_SDA_1; 33 IIC_SCL_1; 34 delay_us(4); 35 IIC_SDA_0; 36 delay_us(4); 37 IIC_SCL_0; 38 } 39 40 //产生IIC停止信号 41 //SCL为高电平时SDA由低变高 42 //IIC空闲时SCL和SDA均输出高电平,这样不会干扰其他设备的收发 43 /* 44 SCL: ̄ ̄ ̄ ̄ 45 SDA:__/ ̄ 46 */ 47 void IIC_Stop(void) 48 { 49 IIC_SDA_0; 50 IIC_SCL_1; 51 delay_us(4); 52 IIC_SDA_1; 53 } 54 55 //等待应答信号到来 56 //返回值:1,接收应答失败 57 // 0,接收应答成功 58 uint8_t IIC_WaitAck(void) 59 { 60 uint8_t errCount = 0; 61 uint8_t ack = 0; 62 63 IIC_SDA_1; 64 delay_us(4); 65 IIC_SCL_1; 66 delay_us(4); 67 68 while(IIC_READ_SDA()) 69 { 70 errCount++; 71 if(errCount > 250){ 72 ack = 1; 73 break; 74 } 75 } 76 IIC_SCL_0; 77 78 return ack; 79 } 80 81 //产生应答ACK 82 //SCL为高电平时SDA为低电平表示应答 83 /* 84 SCL:  ̄ ̄\____ 85 SDA:_______/ ̄ 86 */ 87 void IIC_Ack(void) 88 { 89 IIC_SDA_0; 90 delay_us(4); 91 IIC_SCL_1; 92 delay_us(4); 93 IIC_SCL_0; 94 delay_us(4); 95 IIC_SDA_1; //释放SDA 96 } 97 98 //产生非应答NACK 99 //SCL为高电平时SDA为高电平表示非应答 100 /* 101 SCL:  ̄ ̄\__ 102 SDA: ̄ ̄ ̄ ̄ ̄ ̄ ̄ 103 */ 104 void IIC_NAck(void) 105 { 106 IIC_SDA_1; 107 delay_us(4); 108 IIC_SCL_1; 109 delay_us(4); 110 IIC_SCL_0; 111 delay_us(4); 112 } 113 114 //IIC发送一个字节 115 /* 116 SCL:_ _/ ̄\__ _/ ̄ ̄\__ _/ ̄ ̄\__ _/ ̄ ̄\__ _/ ̄ ̄\__ _/ ̄ ̄\__ _/ ̄ ̄\__ _/ ̄ ̄\__ 117 SDA:-- ------------ -------------- -------------- -------------- -------------- -------------- -------------- -------------- 118 */ 119 void IIC_WriteByte(uint8_t txd) 120 { 121 uint8_t i; 122 123 IIC_SCL_0; 124 for(i = 0; i < 8; i++) 125 { 126 (txd & 0x80) ? IIC_SDA_1 : IIC_SDA_0; 127 txd


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有